package com.it.demo.controller;

import com.it.demo.bean.People;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.management.ClassLoadingMXBean;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;

/**
 * ClassName: MemoryTestController
 * Description: 模拟线上环境OOM
 *
 * @Author: csx
 * @Create: 2025/4/28 - 19:44
 * @version: v1.0
 */
@RestController
public class MemoryTestController {

    /*
      -XX:+PrintGCDetails -XX:MetaspaceSize=64m
      -XX:+HeapDumpOnOutOfMemoryError
      -XX:HeapDumpPath=heap/heapdump.hprof -XX:+PrintGCDateStamps
      -Xms200M  -Xmx200M  -Xloggc:log/gc-oomHeap.log

      jdk9以上建议用如下命令：
      -XX:MetaspaceSize=64m
      -XX:+HeapDumpOnOutOfMemoryError
      -XX:HeapDumpPath=heap/heapdump.hprof
      -Xms200M
      -Xmx200M
      -Xlog:gc*:file=log/gc-oomHeap.log:time,uptime,level,tags

    -Xlog:gc* 替代旧的 GC 日志选项：
        -Xlog:gc* 是 JDK 9+ 中用于启用 GC 日志的统一选项。
        file=log/gc-oomHeap.log 指定日志文件路径。
        time,uptime,level,tags 是日志输出的格式，包含时间戳、JVM 运行时间、日志级别和标签。
     */

    /**
     * 案例1：堆溢出（java.lang.OutOfMemoryError: Java heap space）（http://localhost:8080/add）
     * 堆空间先设置30m
     */
    @RequestMapping("/add")
    public void addObject() {
        ArrayList<People> people = new ArrayList<>();
        while (true){
            people.add(new People());
        }
    }

    /*
        -XX:MetaspaceSize=60m
        -XX:MaxMetaspaceSize=60m
        -Xss512K -XX:+HeapDumpOnOutOfMemoryError
        -XX:HeapDumpPath=heap/heapdumpMeta.hprof
        -XX:SurvivorRatio=8
        -Xms60M -Xmx60M
        -Xlog:gc*=info:file=log/gc-oomMeta.log:time,uptime,level,tags
        -Xlog:class+load=info:file=log/class_loading.log:time,uptime,tags
     */
    /**
     * 案例2：模拟元空间OOM溢出
     */
    @RequestMapping("/metaSpaceOom")
    public void metaSpaceOom() {
        ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
        while (true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(People.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
                System.out.println("我是加强类，输出print之前的加强方法");
                return methodProxy.invokeSuper(o, objects);
            });
            People people = (People) enhancer.create();
//            people.print();
            System.out.println(people.getClass());
            System.out.println("totalClass: " + classLoadingMXBean.getTotalLoadedClassCount());
            System.out.println("activeClass: " + classLoadingMXBean.getLoadedClassCount());
            System.out.println("unloadedClass: " + classLoadingMXBean.getUnloadedClassCount());
        }
    }

}
